/***************************************************************************
 *   File Tranfert.cpp		author belot nicolas (karrakis)            *
 *   define Class Transfert
 *   handle computation on transfert function                              *
 ***************************************************************************
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <cassert>
#include "Transfert.h"

#define max(a,b) a>b?a:b
namespace libtrckr {
Transfert::Transfert( ){
	a=0;
	na=0;
	b=0;
	nb=0;
}

Transfert::Transfert(DynArray<double>A, DynArray<double>B){
	na=A.size();
	nb=B.size();
	a=(double*)malloc(sizeof(double)*na);
	b=(double*)malloc(sizeof(double)*nb);
	
	for(unsigned int i=0;i<na;i++){
		a[i]=A[i];
	}
	for(unsigned int i=1;i<nb;i++){
		b[i]=B[i];
	}
	b[0]=1.0;
}

Transfert::Transfert(const Transfert& t2){
	na=t2.na;
	nb=t2.nb;
	a=(double*)malloc(sizeof(double)*na);
	b=(double*)malloc(sizeof(double)*nb);
	
	memcpy(a,t2.a,na);
	memcpy(b, t2.b,nb);
	/*for(unsigned int i=0;i<na;i++){
		a[i]=t2.a[i];
	}
	for(unsigned int i=1;i<nb;i++){
		b[i]=t2.b[i];
	}*/
	b[0]=1.0;
}

Transfert::~Transfert(){
	free(a);
	free(b);
}
DynArray<double> Transfert::getAs() const {
	DynArray<double> A(na,0.0);
	for(unsigned int i=0;i<na;i++){
		A[i]=a[i];
	}
	return A;
}

DynArray<double> Transfert::getBs() const {
	DynArray<double> B(nb, 0.0);
	for(unsigned int i=0;i<nb;i++){
		B[i]=b[i];
	}
	return B;
}


void Transfert::setAs(DynArray<double> A){
	if(na!=0){
		free(a);
	}
	na = A.size();
	a = (double*)malloc(sizeof(double)*na);
	
	for(unsigned int i=0;i<na;i++){
		a[i]=A[i];
	}
	/*int max = max(a.size(),b.size());
	a.resize(max,0.0);
	b.resize(max,0.0);*/
}

void Transfert::setBs(DynArray<double> B){
	if(nb!=0){
		free(b);
	}
	nb=B.size();
	b = (double*)malloc(sizeof(double)*nb);
	for(unsigned int i=0;i<B.size();i++){
		b[i]=B[i];
	}
	//b.assign(B.begin(),B.end());
	//int max = max(a.size(),b.size());
	b[0]=1.0;
	/*a.resize(max,0.0);
	b.resize(max,0.0);*/
}

void Transfert::operator*=(Transfert& t2){
	unsigned int sa = na + t2.na;
	unsigned int sb = nb + t2.nb;

	double *ra = (double*)malloc(sizeof(double)*sa);

	memset(ra, 0, sizeof(double)*sa);
	/*for(unsigned int i=0;i<sa;i++){
		ra[i]=0.0;
	}*/
	double *rb = (double*)malloc(sizeof(double)*sb);
	memset(rb, 0, sizeof(double)*sb);
	/*for(unsigned int i=0;i<sb;i++){
		rb[i]=0.0;
	}*/
	b[0] = t2.b[0] = 1.0;
	for(unsigned int i=1;i<nb;i++){
			b[i]=-b[i];
	}
	for(unsigned int i=1;i<t2.nb;i++){
			t2.b[i]=-t2.b[i];
	}

	//lent mais sur
	unsigned int amax = na;
	for(unsigned int i=0;i<amax;i++){
		for(unsigned int j=0;j<t2.na;j++){
			ra[i+j]+=a[i] * t2.a[j];
		} 
	}
	
	unsigned int bmax = nb;
	for(unsigned int i=0;i<bmax;i++){
		for(unsigned int j=0; j<t2.nb;j++){
			rb[i+j]+=b[i]*t2.b[j];
		}
	}

	for(unsigned int i=1;i<sb;i++){
			rb[i]=-rb[i];
	}

	for(unsigned int i=1;i<t2.nb;i++){
			t2.b[i]=-t2.b[i];
	}

	free(a);
	free(b);
	na=sa;
	nb=sb;
	a=ra;
	b=rb;
}
Transfert Transfert::operator*(const Transfert& t2) const{
	unsigned int sa = na + t2.na;
	unsigned int sb = nb + t2.nb;

	double *ra = (double*)malloc(sizeof(double)*sa);
	memset(ra,0, sizeof(double)*sa);
	/*for(unsigned int i=0;i<sa;i++){
		ra[i]=0.0;
	}*/
	double *rb = (double*)malloc(sizeof(double)*sb);
	memset(rb, 0, sizeof(double)*sb);
	/*for(unsigned int i=0;i<sb;i++){
		rb[i]=0.0;
	}*/
		
	b[0] = t2.b[0] = 1.0;
	for(unsigned int i=1;i<nb;i++){
			b[i]=-b[i];
	}
	for(unsigned int i=1;i<t2.nb;i++){
			t2.b[i]=-t2.b[i];
	}

	//lent mais sur
	unsigned int amax = na;
	for(unsigned int i=0;i<amax;i++){
		for(unsigned int j=0;j<t2.na;j++){
			ra[i+j]+=a[i] * t2.a[j];
		} 
	}
	
	unsigned int bmax = nb;
	for(unsigned int i=0;i<bmax;i++){
		for(unsigned int j=0; j<t2.nb;j++){
			rb[i+j]+=b[i]*t2.b[j];
		}
	}

	for(unsigned int i=1;i<sb;i++){
			rb[i]=-rb[i];
	}

	for(unsigned int i=1;i<t2.nb;i++){
			t2.b[i]=-t2.b[i];
	}
	
	

	Transfert t;
	t.a=ra;
	t.na=sa;
	t.b=rb;
	t.nb=sb;
	return t;
}

Transfert Transfert::operator+(const Transfert& t2)const{
	int sa = max(na,t2.na) + max(nb,t2.nb);
	int sb = nb + t2.nb;

	double *ra = (double*)malloc(sizeof(double)*sa);
	memset(ra,0,sizeof(double)*sa);
	double *rb = (double*)malloc(sizeof(double)*sb);
	memset(rb,0,sizeof(double)*sb);
	b[0] =  1.0;
	for(unsigned int i=1;i<nb;i++){
			b[i]=-b[i];
	}
	for(unsigned int i=1;i<t2.nb;i++){
			t2.b[i]=-t2.b[i];
	}

	
	
	//run from minimum beetween a.size 
	//multiplying a with B...
	for(unsigned int i=0;i<na;i++){
		for(unsigned int j=0;j<t2.nb;j++){
			ra[i+j]+=a[i]*t2.b[j];
		}	
	}
	//multiplying A with B and adding to ra...
	for(unsigned int i=0;i<t2.na;i++){
		for(unsigned int j=0;j<nb;j++){
			ra[i+j]+=t2.a[i]*b[j];
		}
	}

	for(unsigned int i=0;i<nb;i++){
		for(unsigned int j=0; j<t2.nb;j++){
			rb[i+j]+=b[i]*t2.b[j];
		}
	}
	Transfert t;
	t.a=ra;
	t.na=sa;
	t.b=rb;
	t.nb=sb;	
	return t;
}
void Transfert::operator+=( const Transfert& t2 ){
	int sa = max(na,t2.na) + max(nb,t2.nb);
	int sb = nb + t2.nb;

	double *ra = (double*)malloc(sizeof(double)*sa);
	memset(ra,0,sizeof(double)*sa);
	double *rb = (double*)malloc(sizeof(double)*sb);
	memset(rb,0, sizeof(double)*sa);
	b[0] =  1.0;
	for(unsigned int i=1;i<nb;i++){
			b[i]=-b[i];
	}
	for(unsigned int i=1;i<t2.nb;i++){
			t2.b[i]=-t2.b[i];
	}

	
	
	//run from minimum beetween a.size 
	//multiplying a with B...
	for(unsigned int i=0;i<na;i++){
		for(unsigned int j=0;j<t2.nb;j++){
			ra[i+j]+=a[i]*t2.b[j];
		}	
	}
	//multiplying A with B and adding to ra...
	for(unsigned int i=0;i<t2.na;i++){
		for(unsigned int j=0;j<nb;j++){
			ra[i+j]+=t2.a[i]*b[j];
		}
	}

	for(unsigned int i=0;i<nb;i++){
		for(unsigned int j=0; j<t2.nb;j++){
			rb[i+j]+=b[i]*t2.b[j];
		}
	}
	free(a);
	free(b);
	a=ra;
	na=sa;
	b=rb;
	nb=sb;
	//le woraroud...
}

Transfert Transfert::cascade(const Transfert& t1,const Transfert& t2){
	return t1*t2;
}

Transfert Transfert::parallel(const Transfert& t1,const Transfert& t2){
	return t1+t2;
}

}
